﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Configuration;
using System.ComponentModel;
using System.Threading;

namespace Incendios0_1.tools
{
    
    class AsyncMessageSender<T>
    {
        Func<T, Boolean> send;
        System.Timers.Timer mTimer;
        private LinkedList<T> messageStack;
        private int msgLimit;
        private double waitTime;
        private Thread sender;
        private bool _continue;

        public AsyncMessageSender(Func<T, Boolean> sendFunction)
        {
            msgLimit = Int32.Parse(ConfigurationManager.AppSettings["MessagesStack"]);
            messageStack = new LinkedList<T>();
            mTimer = null;
            this.send = sendFunction;
            sender = new Thread(new ThreadStart(Broadcasting));
            _continue = true;
            sender.Start();
        }

        public AsyncMessageSender(double waitTime, Func<T,Boolean> sendFunction):this(sendFunction)
        {
            this.waitTime = waitTime;
        }

        ~AsyncMessageSender()
        {
            _continue = false;
        }

        public static AsyncMessageSender<T> operator +(AsyncMessageSender<T> container, T newMessage)
        {
            lock (container.messageStack)
            {
                if (container.messageStack.Count < container.msgLimit)
                {
                    container.messageStack.AddLast(newMessage);
                    //container.startSender();
                }
            }
            return container;
        }

        public void Broadcasting()
        {
            T msg;
            while (_continue)
            {
                if (messageStack.Count > 0)
                {
                    lock (messageStack)
                    {
                        msg = messageStack.First.Value;
                        messageStack.RemoveFirst();
                    }
                    send(msg);
                }
                Thread.Sleep(100);
            }
        }

        public void startSender()
        {
            if (mTimer == null)
            {
                mTimer = new System.Timers.Timer(waitTime);
                mTimer.Elapsed += new ElapsedEventHandler(mTimer_Elapsed);
                mTimer_Elapsed(null, null);
                mTimer.Start();
            }
            else
            {
                if (mTimer.Enabled == false)
                {
                    mTimer_Elapsed(null, null);
                    mTimer.Start();
                }
            }
        }

        public bool isEmpty()
        {
            return (messageStack.Count == 0);
        }

        private void mTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (messageStack.Count > 0)
            {
                T msg = messageStack.First.Value;
                messageStack.RemoveFirst();
                send(msg);
                if (messageStack.Count == 0)
                    mTimer.Stop();
            }
        }

        public void Stop()
        {
            /*if (mTimer != null)
            {
                mTimer.Stop();
                mTimer.Dispose();
            }*/
            _continue = false;
        }
    }
}
